package cn.cellcom.agent.struts.action;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.actions.DispatchAction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.cellcom.agent.biz.Org00Biz;
import cn.cellcom.agent.biz.TButtonBiz;
import cn.cellcom.agent.biz.TChannelBiz;
import cn.cellcom.agent.biz.TCrmBiz;
import cn.cellcom.agent.biz.TGroupBiz;
import cn.cellcom.agent.biz.TLwBiz;
import cn.cellcom.agent.biz.TQuestionBiz;
import cn.cellcom.agent.biz.TSessionBiz;
import cn.cellcom.agent.biz.TSettingBiz;
import cn.cellcom.agent.common.AgentConstant;
import cn.cellcom.agent.entity.TSettingEntity;
import cn.cellcom.agent.hql.ApiOrderHql;
import cn.cellcom.agent.online.client.ClientManager;
import cn.cellcom.agent.online.client.VisitorClient;
import cn.cellcom.agent.online.handler.TraceHandler;
import cn.cellcom.agent.online.iq.ProcessorResult;
import cn.cellcom.agent.online.iq.agent.LwDetailProcessor;
import cn.cellcom.agent.online.iq.visitor.ButtonProcessor;
import cn.cellcom.agent.online.iq.visitor.GetGroupListProcessor;
import cn.cellcom.agent.online.iq.visitor.LwProcessor;
import cn.cellcom.agent.online.iq.visitor.SatisfyProcessor;
import cn.cellcom.agent.online.iq.visitor.VisitorProcessors;
import cn.cellcom.agent.online.message.MessageConstant;
import cn.cellcom.agent.online.wrapper.SessionWrapper;
import cn.cellcom.agent.pojo.TChannel;
import cn.cellcom.agent.pojo.TCrm;
import cn.cellcom.agent.pojo.TLw;
import cn.cellcom.agent.pojo.TOrg;
import cn.cellcom.agent.pojo.TTrace;
import cn.cellcom.agent.struts.form.VisitorForm;
import cn.cellcom.jar.biz.AbstractBiz;
import cn.cellcom.jar.env.Env;
import cn.cellcom.jar.pagination.AbstractPaginationBiz;
import cn.cellcom.jar.pagination.IPaginationBiz;
import cn.cellcom.jar.util.CopyUtil;
import cn.cellcom.jar.util.LogUtil;
import cn.cellcom.jar.util.MyException;

/**
 * 访客端访问逻辑
 * 
 * @author 郑余杰
 */
public class VisitorDpAct extends DispatchAction {

	private Logger log = LoggerFactory.getLogger(this.getClass());

	private TSettingBiz sbiz;

	private TButtonBiz bbiz;

	private Org00Biz obiz;

	private TSessionBiz ssbiz;

	private TGroupBiz gbiz;

	private TQuestionBiz qbiz;

	private TCrmBiz cbiz;

	private TChannelBiz chbiz;

	private TLwBiz lbiz;

	private IPaginationBiz pbiz;

	/**
	 * 获取配置信息
	 * 
	 * @param mapping
	 * @param form
	 * @param req
	 * @param rep
	 * @return
	 */
	public ActionForward getConfig(ActionMapping mapping, ActionForm form, HttpServletRequest req, HttpServletResponse rep) {

		VisitorForm cf = (VisitorForm) form;
		String crmId = (String) req.getSession().getAttribute(AgentConstant.CRM_ID_IN_SESSION);
		log.info("[{}] get config from ip[{}]", crmId, req.getRemoteAddr());
		try {
			TSettingEntity setting = sbiz.getChannelSetting(cf.getPid(), cf.getChannel(), false);
			int advertHeight = 0;
			setting.setWindowHeight(setting.getWindowHeight() + advertHeight);
			req.getSession().setAttribute("advertHeight", advertHeight);
			TChannel channel = chbiz.getChannelByNo(cf.getOrg(), cf.getChannel());
			Map<String, Object> map = new HashMap<String, Object>();
			map.put("setting", setting);
			map.put("channel", channel);
			VisitorClient visitorClient = (VisitorClient) ClientManager.getInstance().getClient(crmId);
			if (visitorClient != null) {
				map.put("crm", visitorClient.getCrm());
				SessionWrapper sessionOfPid = visitorClient.getSessionByPid(cf.getPid());
				if (sessionOfPid != null) {
					map.put("session", sessionOfPid.getSession());
				}
				log.info("[{}] have exist client[{}] and session[{}] for pid[{}]", crmId, visitorClient, (sessionOfPid == null ? null : sessionOfPid
						.getId()), cf.getPid());
			}

			Response.succObject(rep, map);

			TraceHandler.record(cf.getOrg() == null ? cf.getPid() : cf.getOrg(), cf.getPid(), req, rep);
		} catch (MyException e) {
			req.setAttribute("result", "请求参数有误[EXC-10009]");
			log.error("pid [{}] and channel[{}] get config width cid[{}] fail.", cf.getPid(), cf.getChannel(), crmId);
			log.error("", e.getException());
			return mapping.findForward("error2");
		}
		return null;
	}

	/**
	 * 登陆
	 * 
	 * @param mapping
	 * @param form
	 * @param req
	 * @param rep
	 * @return
	 */
	public ActionForward logon(ActionMapping mapping, ActionForm form, HttpServletRequest req, HttpServletResponse rep) {
		VisitorForm cf = (VisitorForm) form;
		log.info("[{}] <LOGON> from ip[{}]", cf.getTid(), req.getRemoteAddr());

		if (StringUtils.isBlank(cf.getPid()) || StringUtils.isBlank(cf.getChannel())) {
			req.setAttribute("result", "请求参数有误[LOGON-10000]");
			log.error("[{}] logon but not pid[{}] or channel[{}].", cf.getTid(), cf.getPid(), cf.getChannel());
			return mapping.findForward("error2");
		}
		TSettingEntity setting;
		TOrg org = null;
		try {
			setting = sbiz.getChannelSetting(cf.getPid(), cf.getChannel(), false);
			if (setting == null) {
				req.setAttribute("result", "请求参数有误[SETTING-10002]");
				log.error("[{}] logon but get setting fail for pid[{}] and channel[{}].", cf.getTid(), cf.getPid(), cf.getChannel());
				return mapping.findForward("error2");
			}
			
			org = obiz.getByPid(cf.getPid());
			if(org == null) {
				req.setAttribute("result", "您(" + cf.getPid() + ")的使用权已过期，请联系系统管理员");
				return mapping.findForward("error2");
			}
			setting.setOrgName(org.getName());
			req.setAttribute("orgHeader", setting.getOrgHeader());
		} catch (MyException e) {
			req.setAttribute("result", "请求参数有误[SETTING-10001]");
			log.error("[{}] logon but get setting fail for pid[{}] and channel[{}].", cf.getTid(), cf.getPid(), cf.getChannel());
			log.error("", e.getException());
			return mapping.findForward("error2");
		}
		req.setAttribute("bg", setting.getWindowBackgroundColor());
		req.setAttribute("orgName", setting.getOrgName());

		TCrm crm = null;
		try {
			crm = cbiz.getOrCreateCrm(req, rep, cf, org, setting);
		} catch (MyException e) {
			req.setAttribute("result", StringUtils.isBlank(e.getMsg()) ? "请求参数有误[EXC-10003]" : e.getMsg());
			log.error(cf.getTid() + " catch exception while logon.", e.getException());
			return mapping.findForward("error2");
		}

		if (crm == null) {
			req.setAttribute("result", "请求参数有误[CRM-10004]");
			log.error("[{}] logon but not exist crm.", cf.getTid());
			return mapping.findForward("error2");
		} else if (crm.getStatus() != null && AgentConstant.VISITOR_STATUS.NO.ordinal() == crm.getStatus()) {
			req.setAttribute("result", "您暂时无法请求客服，请稍后访问[CRM-10005]");
			log.error("[{}] logon but it is forbiden.", crm.getId());
			return mapping.findForward("error2");
		} else {
			// 这个是给前端用于采用get的方式获取crm信息对象
			req.getSession().setAttribute(AgentConstant.CRM_ID_IN_SESSION, crm.getId());

			// 访客请求logon之前的访问记录
			TraceHandler.saveTempRecordToMongoDb(crm.getId(), req.getSession());
		}
		try {
			VisitorClient visitorClient = (VisitorClient) ClientManager.getInstance().getClient(crm.getId());
			if (visitorClient == null) {
				visitorClient = new VisitorClient(chbiz, ssbiz, gbiz, qbiz, cf.getChannel(), crm, req.getSession().getId());
				ClientManager.getInstance().record(visitorClient);
				log.info("[{}] have no client, so create it [{}], sequence[{}]", crm.getId(), visitorClient, visitorClient.getSequence());
			} else {
				visitorClient.setSequence();
				log.info("[{}] have exist client[{}], new sequence[{}]", crm.getId(), visitorClient, visitorClient.getSequence());
			}
			req.setAttribute("sequence", visitorClient.getSequence());
			
			SessionWrapper sessionOfPid = visitorClient.getSessionByPid(cf.getPid());
			if (sessionOfPid == null) {
				TTrace last = TraceHandler.updateLastRecord(cf.getPid(), crm.getId(), req.getSession().getId());

				sessionOfPid = visitorClient.initSession(cf.getPid(), setting, req.getRemoteAddr(), last);
				sessionOfPid.setSetting(setting);

			} else {
				log.info("[{}] have exist session[{}] for pid[{}]", crm.getId(), sessionOfPid.getId(), cf.getPid());
				sessionOfPid.setSetting(setting);
			}
			sessionOfPid.join(visitorClient, null);

			visitorClient.sendSession(sessionOfPid.getSession());
			visitorClient.notifyStatus(cf.getPid(), null);
		} catch (MyException e) {
			req.setAttribute("result", "请求参数有误[EXC-10009]");
			log.error(crm.getId() + "[{}] catch exception while logon.", e.getException());
			return mapping.findForward("error2");
		}
		if ("java".equals(cf.getApi())) {
			Response.succObject(rep, crm);
			return null;
		}
		return mapping.findForward("visitor");
	}

	/**
	 * 访客端发起消息
	 * 
	 * @param mapping
	 * @param form
	 * @param req
	 * @param rep
	 * @return
	 */
	public ActionForward processor(ActionMapping mapping, ActionForm form, HttpServletRequest req, HttpServletResponse rep) {
		VisitorForm cf = (VisitorForm) form;

		if (StringUtils.isBlank(cf.getCid())) {
			Response.err(rep, "请求参数有误[20000]");
			return null;
		}
		VisitorClient client = (VisitorClient) ClientManager.getInstance().getClient(cf.getCid());
		if (client == null) {
			Response.err(rep, "20001");
			log.warn("[{}] have no client, return [20001]", cf.getCid());
			return null;
		} else if(!client.getSequence().equals(cf.getSequence())) {//如果多次登陆，前面的界面则不动态获取消息
			Response.err(rep, "20002");
			return null;
		}

		Map<String, AbstractBiz> bizs = new HashMap<String, AbstractBiz>();
		if (SatisfyProcessor.NAME.equals(cf.getEvent())) {
			bizs.put("ssbiz", ssbiz);
			bizs.put("sbiz", sbiz);
		} else if (ButtonProcessor.NAME.equals(cf.getEvent())) {
			bizs.put("bbiz", bbiz);
		} else if (GetGroupListProcessor.NAME.equals(cf.getEvent()) || MessageConstant.MESSAGE_EVENT.ENTER_GROUP.name().equals(cf.getEvent())) {
			bizs.put("gbiz", gbiz);
			bizs.put("chbiz", chbiz);
		} else if (LwProcessor.NAME.equals(cf.getEvent())) {
			try { 
				TLw lw = new TLw();
				CopyUtil.copy(req, lw, null, false);
				cf.setObject(lw);
			} catch (MyException e) {
			}
			bizs.put("sbiz", ssbiz);
		} else if (LwDetailProcessor.NAME.equals(cf.getEvent())) {
			bizs.put("lbiz", lbiz);
		}
		ProcessorResult result = VisitorProcessors.createProcessors().process(bizs, client, cf);
		if (result != null) {
			Object dt = result.getData();
			if (dt == null) {
				dt = "";
			}
			if (result.isSuccess()) {
				if (dt instanceof List) {
					Response.succ(rep, (List) dt);
				} else if (dt instanceof String) {
					Response.succ(rep, String.valueOf(dt));
				} else {
					Response.succObject(rep, dt);
				}
			} else {
				Response.err(rep, String.valueOf(dt));
			}
			if (StringUtils.isNotBlank(cf.getEvent())) {
				log.info("[{}] <IQ_MESSAGE> handle result : " + cf.getEvent() + "[{}]", client.getId(), dt);
			}
			return null;
		} else {
			log.error("[{}] <IQ_MESSAGE> send fail for event[{}]", client.getId(), cf.getEvent());
		}
		return null;
	}

	/**
	 * 查询记录
	 * 
	 * @param mapping
	 * @param fm
	 * @param req
	 * @param rep
	 * @return
	 */
	public ActionForward orderList(ActionMapping mapping, ActionForm form, HttpServletRequest req, HttpServletResponse rep) {
		form = (ActionForm) AbstractPaginationBiz.getPaginationActionForm(req, form);
		List list = null;
		try {
			pbiz.setPageSize(5);
			list = pbiz.pagination(mapping, form, req, new ApiOrderHql()).getDataResult();

			req.setAttribute(Env.DATA_NAME, list);
		} catch (MyException e) {
			return LogUtil.e(this.clazz, "操作出现错误", e, mapping, req);
		}
		return mapping.findForward("orderList");
	}

	public void setGbiz(TGroupBiz gbiz) {
		this.gbiz = gbiz;
	}

	public void setSbiz(TSettingBiz sbiz) {
		this.sbiz = sbiz;
	}

	public void setObiz(Org00Biz obiz) {
		this.obiz = obiz;
	}

	public void setSsbiz(TSessionBiz ssbiz) {
		this.ssbiz = ssbiz;
	}

	public void setQbiz(TQuestionBiz qbiz) {
		this.qbiz = qbiz;
	}

	public void setBbiz(TButtonBiz bbiz) {
		this.bbiz = bbiz;
	}

	public void setCbiz(TCrmBiz cbiz) {
		this.cbiz = cbiz;
	}

	public void setChbiz(TChannelBiz chbiz) {
		this.chbiz = chbiz;
	}

	public void setLbiz(TLwBiz lbiz) {
		this.lbiz = lbiz;
	}

	public void setPbiz(IPaginationBiz pbiz) {
		this.pbiz = pbiz;
	}

}
